/*
 *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the License); you may
 *  not use this file except in compliance with the License.
 *
 *  http:
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mem.h"
#include "sm2.h"
#include "sm2_common.h"

extern const peace_sm2_BN peace_sm2_N;
extern const peace_sm2_BN peace_sm2_ONE;

int peace_sm2_do_sign(const peace_sm2_KEY *key, const uint8_t dgst[32], peace_sm2_SIGNATURE *sig)
{
	peace_sm2_JACOBIAN_POINT _P, *P = &_P;
	peace_sm2_BN d;
	peace_sm2_BN d_inv;
	peace_sm2_BN e;
	peace_sm2_BN k;
	peace_sm2_BN x;
	peace_sm2_BN t;
	peace_sm2_BN r;
	peace_sm2_BN s;
	uint8_t Bn_Zero_dowhile[2] = {0};

	peace_sm2_bn_from_bytes(d, key->private_key);

	peace_sm2_fn_add(d_inv, d, peace_sm2_ONE);
	if (peace_sm2_bn_is_zero(d_inv))
	{
		return E_ERROR;
	}
	peace_sm2_fn_inv(d_inv, d_inv);

	peace_sm2_bn_from_bytes(e, dgst);

	do
	{

		Bn_Zero_dowhile[0] = 0;
		Bn_Zero_dowhile[1] = 0;

		do
		{
			if (peace_sm2_fn_rand(k) != 1)
			{
				return E_ERROR;
			}
		} while (peace_sm2_bn_is_zero(k));

		peace_sm2_jacobian_point_mul_generator(P, k);
		peace_sm2_jacobian_point_get_xy(P, x, NULL);

		if (peace_sm2_bn_cmp(e, peace_sm2_N) >= 0)
		{
			peace_sm2_bn_sub(e, e, peace_sm2_N);
		}
		if (peace_sm2_bn_cmp(x, peace_sm2_N) >= 0)
		{
			peace_sm2_bn_sub(x, x, peace_sm2_N);
		}
		peace_sm2_fn_add(r, e, x);

		peace_sm2_bn_add(t, r, k);
		if (peace_sm2_bn_is_zero(r) || peace_sm2_bn_cmp(t, peace_sm2_N) == 0)
		{

			Bn_Zero_dowhile[0] = 1;
		}

		if (Bn_Zero_dowhile[0] != 1)
		{

			peace_sm2_fn_mul(t, r, d);
			peace_sm2_fn_sub(k, k, t);
			peace_sm2_fn_mul(s, d_inv, k);
		}

		if (peace_sm2_bn_is_zero(s))
		{
			Bn_Zero_dowhile[1] = 1;
		}
	} while ((Bn_Zero_dowhile[0] != 0) || (Bn_Zero_dowhile[1] != 0));

	peace_sm2_bn_to_bytes(r, sig->r);
	peace_sm2_bn_to_bytes(s, sig->s);

	return 1;
}

int peace_sm2_do_verify(const peace_sm2_KEY *key, const uint8_t dgst[32], const peace_sm2_SIGNATURE *sig)
{
	peace_sm2_JACOBIAN_POINT _P, *P = &_P;
	peace_sm2_JACOBIAN_POINT _R, *R = &_R;
	peace_sm2_BN r;
	peace_sm2_BN s;
	peace_sm2_BN e;
	peace_sm2_BN x;
	peace_sm2_BN t;

	peace_sm2_jacobian_point_from_bytes(P, (const uint8_t *)&key->public_key);

	peace_sm2_bn_from_bytes(r, sig->r);
	peace_sm2_bn_from_bytes(s, sig->s);

	if (peace_sm2_bn_is_zero(r) == 1 || peace_sm2_bn_cmp(r, peace_sm2_N) >= 0 || peace_sm2_bn_is_zero(s) == 1 || peace_sm2_bn_cmp(s, peace_sm2_N) >= 0)
	{

		return E_ERROR;
	}

	peace_sm2_bn_from_bytes(e, dgst);

	peace_sm2_fn_add(t, r, s);
	if (peace_sm2_bn_is_zero(t))
	{

		return E_ERROR;
	}

	peace_sm2_jacobian_point_mul_sum(R, t, P, s);
	peace_sm2_jacobian_point_get_xy(R, x, NULL);

	if (peace_sm2_bn_cmp(e, peace_sm2_N) >= 0)
	{
		peace_sm2_bn_sub(e, e, peace_sm2_N);
	}
	if (peace_sm2_bn_cmp(x, peace_sm2_N) >= 0)
	{
		peace_sm2_bn_sub(x, x, peace_sm2_N);
	}
	peace_sm2_fn_add(e, e, x);

	if (peace_sm2_bn_cmp(e, r) != 0)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_signature_to_der(const peace_sm2_SIGNATURE *sig, uint8_t **out, size_t *outlen)
{
	size_t len = 0;
	if (!sig)
	{
		return 0;
	}
	if (peace_asn1_integer_to_der(sig->r, 32, NULL, &len) != 1 || peace_asn1_integer_to_der(sig->s, 32, NULL, &len) != 1 || peace_asn1_sequence_header_to_der(len, out, outlen) != 1 || peace_asn1_integer_to_der(sig->r, 32, out, outlen) != 1 || peace_asn1_integer_to_der(sig->s, 32, out, outlen) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_signature_from_der(peace_sm2_SIGNATURE *sig, const uint8_t **in, size_t *inlen)
{
	int ret;
	const uint8_t *d;
	size_t dlen;
	const uint8_t *r;
	size_t rlen;
	const uint8_t *s;
	size_t slen;

	if ((ret = peace_asn1_type_from_der(peace_asn1_TAG_SEQUENCE, &d, &dlen, in, inlen)) != 1)
	{
		if (ret < 0)

			return ret;
	}
	if (peace_asn1_integer_from_der(&r, &rlen, &d, &dlen) != 1 || peace_asn1_integer_from_der(&s, &slen, &d, &dlen) != 1 || peace_asn1_length_le(rlen, 32) != 1 || peace_asn1_length_le(slen, 32) != 1 || peace_asn1_length_is_zero(dlen) != 1)
	{

		return E_ERROR;
	}
	memset(sig, 0, sizeof(*sig));
	memcpy(sig->r + 32 - rlen, r, rlen);
	memcpy(sig->s + 32 - slen, s, slen);
	return 1;
}

int peace_sm2_sign_internal(const peace_sm2_KEY *key, const uint8_t dgst[32], uint8_t *sigbuf, uint8_t *sign_R, uint8_t *sign_S, size_t *siglen)
{
	peace_sm2_SIGNATURE Sign;
	if (!key || !dgst || !sigbuf || !siglen)
	{

		return E_ERROR;
	}

	if (peace_sm2_do_sign(key, dgst, &Sign) != 1)
	{

		return E_ERROR;
	}

	*siglen = 0;
	for (int i = 0; i < 32; i++)
	{
		sign_R[i] = Sign.r[i];
		sign_S[i] = Sign.s[i];
	}
	if (peace_sm2_signature_to_der(&Sign, &sigbuf, siglen) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_sign_fixlen(const peace_sm2_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig)
{
	unsigned int trys = 200;
	uint8_t buf[peace_sm2_MAX_SIGNATURE_SIZE];
	uint8_t Sig_R[32];
	uint8_t Sig_S[32];
	size_t len;

	switch (siglen)
	{
	case peace_sm2_signature_compact_size:
	case peace_sm2_signature_typical_size:
	case peace_sm2_signature_max_size:
		break;
	default:

		return E_ERROR;
	}

	while (trys--)
	{
		if (peace_sm2_sign_internal(key, dgst, buf, Sig_R, Sig_S, &len) != 1)
		{

			return E_ERROR;
		}
		if (len == siglen)
		{
			memcpy(sig, buf, len);
			return 1;
		}
	}

	return E_ERROR;
}

int peace_sm2_verify_internal(const peace_sm2_KEY *key, const uint8_t dgst[32], const uint8_t *sigbuf, size_t siglen)
{
	peace_sm2_SIGNATURE sig;

	if (!key || !dgst || !sigbuf || !siglen)
	{

		return E_ERROR;
	}

	if (peace_sm2_signature_from_der(&sig, &sigbuf, &siglen) != 1 || peace_asn1_length_is_zero(siglen) != 1)
	{

		return E_ERROR;
	}
	if (peace_sm2_do_verify(key, dgst, &sig) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int sm2ComputeZ(uint8_t z[32], const peace_sm2_POINT *pub, const char *id, size_t idlen)
{
	peace_sm3_CTX ctx;
	uint8_t zin[18 + 32 * 6] = {
		0x00,
		0x80,
		0x31,
		0x32,
		0x33,
		0x34,
		0x35,
		0x36,
		0x37,
		0x38,
		0x31,
		0x32,
		0x33,
		0x34,
		0x35,
		0x36,
		0x37,
		0x38,
		0xFF,
		0xFF,
		0xFF,
		0xFE,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0x00,
		0x00,
		0x00,
		0x00,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFF,
		0xFC,
		0x28,
		0xE9,
		0xFA,
		0x9E,
		0x9D,
		0x9F,
		0x5E,
		0x34,
		0x4D,
		0x5A,
		0x9E,
		0x4B,
		0xCF,
		0x65,
		0x09,
		0xA7,
		0xF3,
		0x97,
		0x89,
		0xF5,
		0x15,
		0xAB,
		0x8F,
		0x92,
		0xDD,
		0xBC,
		0xBD,
		0x41,
		0x4D,
		0x94,
		0x0E,
		0x93,
		0x32,
		0xC4,
		0xAE,
		0x2C,
		0x1F,
		0x19,
		0x81,
		0x19,
		0x5F,
		0x99,
		0x04,
		0x46,
		0x6A,
		0x39,
		0xC9,
		0x94,
		0x8F,
		0xE3,
		0x0B,
		0xBF,
		0xF2,
		0x66,
		0x0B,
		0xE1,
		0x71,
		0x5A,
		0x45,
		0x89,
		0x33,
		0x4C,
		0x74,
		0xC7,
		0xBC,
		0x37,
		0x36,
		0xA2,
		0xF4,
		0xF6,
		0x77,
		0x9C,
		0x59,
		0xBD,
		0xCE,
		0xE3,
		0x6B,
		0x69,
		0x21,
		0x53,
		0xD0,
		0xA9,
		0x87,
		0x7C,
		0xC6,
		0x2A,
		0x47,
		0x40,
		0x02,
		0xDF,
		0x32,
		0xE5,
		0x21,
		0x39,
		0xF0,
		0xA0,
	};

	if (!z || !pub || !id)
	{

		return E_ERROR;
	}

	memcpy(&zin[18 + 32 * 4], pub->x, 32);
	memcpy(&zin[18 + 32 * 5], pub->y, 32);

	peace_sm3_Init(&ctx);
	if (strcmp(id, peace_sm2_DEFAULT_ID) == 0)
	{
		peace_sm3_update(&ctx, zin, sizeof(zin));
	}
	else
	{
		uint8_t idbits[2];
		idbits[0] = (uint8_t)(idlen >> 5);
		idbits[1] = (uint8_t)(idlen << 3);
		peace_sm3_update(&ctx, idbits, 2);
		peace_sm3_update(&ctx, (uint8_t *)id, idlen);
		peace_sm3_update(&ctx, zin + 18, 32 * 6);
	}
	peace_sm3_finish(&ctx, z);
	return 1;
}

Std_ReturnType peace_sm2_sign_init(peace_sm2_SIGN_CTX *ctx, const peace_sm2_KEY *key, const char *id, size_t idlen)
{
	if (!ctx || !key)
	{

		return E_NOT_OK;
	}
	ctx->key = *key;
	peace_sm3_Init(&ctx->peace_sm3_ctx);

	if (id)
	{
		uint8_t z[peace_sm3_DIGEST_SIZE];
		if (idlen <= 0 || idlen > peace_sm2_MAX_ID_LENGTH)
		{

			return E_NOT_OK;
		}
		sm2ComputeZ(z, &key->public_key, id, idlen);
		peace_sm3_update(&ctx->peace_sm3_ctx, z, sizeof(z));
	}
	return E_OK;
}

Std_ReturnType peace_sm2_sign_update(peace_sm2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
	if (!ctx)
	{

		return E_NOT_OK;
	}
	if (data && datalen > 0)
	{
		peace_sm3_update(&ctx->peace_sm3_ctx, data, datalen);
	}
	return E_OK;
}

Std_ReturnType peace_sm2_sign_finish(peace_sm2_SIGN_CTX *ctx, uint8_t *sig, uint8_t *Sig_R, uint8_t *Sig_S, size_t *siglen)
{
	uint8_t dgst[peace_sm3_DIGEST_SIZE];

	if (!ctx || !sig || !siglen)
	{

		return E_NOT_OK;
	}
	peace_sm3_finish(&ctx->peace_sm3_ctx, dgst);
	printf("digest\n");
	for(int i = 0; i < peace_sm3_DIGEST_SIZE; i++)
	{
		printf("%02x", dgst[i]);
	}
	printf("\n");
	if (peace_sm2_sign_internal(&ctx->key, dgst, sig, Sig_R, Sig_S, siglen) != 1)
	{

		return E_NOT_OK;
	}
	return E_OK;
}

int peace_sm2_sign_finish_fixlen(peace_sm2_SIGN_CTX *ctx, size_t siglen, uint8_t *sig)
{
	uint8_t dgst[peace_sm3_DIGEST_SIZE];

	if (!ctx || !sig || !siglen)
	{

		return E_ERROR;
	}
	peace_sm3_finish(&ctx->peace_sm3_ctx, dgst);
	if (peace_sm2_sign_fixlen(&ctx->key, dgst, siglen, sig) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_verify_init(peace_sm2_SIGN_CTX *ctx, const peace_sm2_KEY *key, const char *id, size_t idlen)
{
	if (!ctx || !key)
	{

		return E_ERROR;
	}
	memset(ctx, 0, sizeof(*ctx));
	ctx->key.public_key = key->public_key;
	peace_sm3_Init(&ctx->peace_sm3_ctx);

	if (id)
	{
		uint8_t z[peace_sm3_DIGEST_SIZE];
		if (idlen <= 0 || idlen > peace_sm2_MAX_ID_LENGTH)
		{

			return E_ERROR;
		}
		sm2ComputeZ(z, &key->public_key, id, idlen);
		peace_sm3_update(&ctx->peace_sm3_ctx, z, sizeof(z));
	}
	return 1;
}

int peace_sm2_verify_update(peace_sm2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
	if (!ctx)
	{
		return E_ERROR;
	}
	if (data && datalen > 0)
	{
		peace_sm3_update(&ctx->peace_sm3_ctx, data, datalen);
	}
	return 1;
}

int peace_sm2_verify_finish(peace_sm2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen)
{
	uint8_t dgst[peace_sm3_DIGEST_SIZE];

	if (!ctx || !sig)
	{

		return E_ERROR;
	}
	peace_sm3_finish(&ctx->peace_sm3_ctx, dgst);
	if (peace_sm2_verify_internal(&ctx->key, dgst, sig, siglen) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

static int peace_sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out)
{
	peace_sm3_CTX ctx;
	uint8_t counter_be[4];
	uint8_t dgst[peace_sm3_DIGEST_SIZE];
	uint32_t counter = 1;
	size_t len;

	while (outlen)
	{
		PUTU32(counter_be, counter);
		counter++;

		peace_sm3_Init(&ctx);
		peace_sm3_update(&ctx, in, inlen);
		peace_sm3_update(&ctx, counter_be, sizeof(counter_be));
		peace_sm3_finish(&ctx, dgst);

		len = outlen < peace_sm3_DIGEST_SIZE ? outlen : peace_sm3_DIGEST_SIZE;
		memcpy(out, dgst, len);
		out += len;
		outlen -= len;
	}

	memset(&ctx, 0, sizeof(peace_sm3_CTX));
	memset(dgst, 0, sizeof(dgst));
	return 1;
}

static int all_zero(const uint8_t *buf, size_t len)
{
	size_t i;
	for (i = 0; i < len; i++)
	{
		if (buf[i])
		{
			return 0;
		}
	}
	return 1;
}

int peace_sm2_do_encrypt(const peace_sm2_KEY *key, const uint8_t *in, size_t inlen, peace_sm2_CIPHERTEXT *out)
{
	peace_sm2_BN k;
	peace_sm2_JACOBIAN_POINT _P, *P = &_P;
	peace_sm2_JACOBIAN_POINT _C1, *C1 = &_C1;
	peace_sm2_JACOBIAN_POINT _kP, *kP = &_kP;
	uint8_t x2y2[64];
	peace_sm3_CTX peace_sm3_ctx;

	if (!(peace_sm2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= peace_sm2_MAX_PLAINTEXT_SIZE))
	{

		return E_ERROR;
	}

	peace_sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key);

retry:

	do
	{
		if (peace_sm2_fn_rand(k) != 1)
		{

			return E_ERROR;
		}
	} while (peace_sm2_bn_is_zero(k));

	peace_sm2_jacobian_point_mul_generator(C1, k);
	peace_sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point);

	peace_sm2_jacobian_point_mul(kP, k, P);
	peace_sm2_jacobian_point_to_bytes(kP, x2y2);

	peace_sm2_kdf(x2y2, 64, inlen, out->ciphertext);

	if (all_zero(out->ciphertext, inlen))
	{
		goto retry;
	}

	peace_sm2_memxor(out->ciphertext, out->ciphertext, in, inlen);
	out->ciphertext_size = (uint32_t)inlen;

	peace_sm3_Init(&peace_sm3_ctx);
	peace_sm3_update(&peace_sm3_ctx, x2y2, 32);
	peace_sm3_update(&peace_sm3_ctx, in, inlen);
	peace_sm3_update(&peace_sm3_ctx, x2y2 + 32, 32);
	peace_sm3_finish(&peace_sm3_ctx, out->hash);

	memset(k, 0, sizeof(k));
	memset(kP, 0, sizeof(peace_sm2_JACOBIAN_POINT));
	memset(x2y2, 0, sizeof(x2y2));
	return 1;
}

int peace_sm2_do_encrypt_fixlen(const peace_sm2_KEY *key, const uint8_t *in, size_t inlen, int point_size, peace_sm2_CIPHERTEXT *out)
{
	unsigned int trys = 200;
	peace_sm2_BN k;
	peace_sm2_JACOBIAN_POINT _P, *P = &_P;
	peace_sm2_JACOBIAN_POINT _C1, *C1 = &_C1;
	peace_sm2_JACOBIAN_POINT _kP, *kP = &_kP;
	uint8_t x2y2[64];
	peace_sm3_CTX peace_sm3_ctx;

	if (!(peace_sm2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= peace_sm2_MAX_PLAINTEXT_SIZE))
	{

		return E_ERROR;
	}

	switch (point_size)
	{
	case peace_sm2_ciphertext_compact_point_size:
	case peace_sm2_ciphertext_typical_point_size:
	case peace_sm2_ciphertext_max_point_size:
		break;
	default:

		return E_ERROR;
	}

	peace_sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key);

retry:

	do
	{
		if (peace_sm2_fn_rand(k) != 1)
		{

			return E_ERROR;
		}
	} while (peace_sm2_bn_is_zero(k));

	peace_sm2_jacobian_point_mul_generator(C1, k);
	peace_sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point);

	if (trys)
	{
		size_t len = 0;
		peace_asn1_integer_to_der(out->point.x, 32, NULL, &len);
		peace_asn1_integer_to_der(out->point.y, 32, NULL, &len);
		if (len != point_size)
		{
			trys--;
			goto retry;
		}
	}
	else
	{
		memset(k, 0, sizeof(k));

		return E_ERROR;
	}

	peace_sm2_jacobian_point_mul(kP, k, P);
	peace_sm2_jacobian_point_to_bytes(kP, x2y2);

	peace_sm2_kdf(x2y2, 64, inlen, out->ciphertext);

	if (all_zero(out->ciphertext, inlen))
	{
		goto retry;
	}

	peace_sm2_memxor(out->ciphertext, out->ciphertext, in, inlen);
	out->ciphertext_size = (uint32_t)inlen;

	peace_sm3_Init(&peace_sm3_ctx);
	peace_sm3_update(&peace_sm3_ctx, x2y2, 32);
	peace_sm3_update(&peace_sm3_ctx, in, inlen);
	peace_sm3_update(&peace_sm3_ctx, x2y2 + 32, 32);
	peace_sm3_finish(&peace_sm3_ctx, out->hash);

	memset(k, 0, sizeof(k));
	memset(kP, 0, sizeof(peace_sm2_JACOBIAN_POINT));
	memset(x2y2, 0, sizeof(x2y2));
	return 1;
}

int peace_sm2_do_decrypt(const peace_sm2_KEY *key, const peace_sm2_CIPHERTEXT *in, uint8_t *out, size_t *outlen)
{
	int ret = -1;
	peace_sm2_BN d;
	peace_sm2_JACOBIAN_POINT _C1, *C1 = &_C1;
	uint8_t x2y2[64];
	peace_sm3_CTX peace_sm3_ctx;
	uint8_t hash[32];

	peace_sm2_jacobian_point_from_bytes(C1, (uint8_t *)&in->point);
	if (!peace_sm2_jacobian_point_is_on_curve(C1))
	{

		return E_ERROR;
	}

	peace_sm2_bn_from_bytes(d, key->private_key);
	peace_sm2_jacobian_point_mul(C1, d, C1);

	peace_sm2_jacobian_point_to_bytes(C1, x2y2);
	peace_sm2_kdf(x2y2, 64, in->ciphertext_size, out);
	if (all_zero(out, in->ciphertext_size))
	{

		goto end;
	}

	peace_sm2_memxor(out, out, in->ciphertext, in->ciphertext_size);
	*outlen = in->ciphertext_size;

	peace_sm3_Init(&peace_sm3_ctx);
	peace_sm3_update(&peace_sm3_ctx, x2y2, 32);
	peace_sm3_update(&peace_sm3_ctx, out, in->ciphertext_size);
	peace_sm3_update(&peace_sm3_ctx, x2y2 + 32, 32);
	peace_sm3_finish(&peace_sm3_ctx, hash);

	if (memcmp(in->hash, hash, sizeof(hash)) != 0)
	{

		goto end;
	}
	ret = 1;

end:
	memset(d, 0, sizeof(d));
	memset(C1, 0, sizeof(peace_sm2_JACOBIAN_POINT));
	memset(x2y2, 0, sizeof(x2y2));
	return ret;
}

int peace_sm2_ciphertext_to_der(const peace_sm2_CIPHERTEXT *C, uint8_t **out, size_t *outlen)
{
	size_t len = 0;
	if (!C)
	{
		return 0;
	}
	if (peace_asn1_integer_to_der(C->point.x, 32, NULL, &len) != 1 || peace_asn1_integer_to_der(C->point.y, 32, NULL, &len) != 1 || peace_asn1_octet_string_to_der(C->hash, 32, NULL, &len) != 1 || peace_asn1_octet_string_to_der(C->ciphertext, C->ciphertext_size, NULL, &len) != 1 || peace_asn1_sequence_header_to_der(len, out, outlen) != 1 || peace_asn1_integer_to_der(C->point.x, 32, out, outlen) != 1 || peace_asn1_integer_to_der(C->point.y, 32, out, outlen) != 1 || peace_asn1_octet_string_to_der(C->hash, 32, out, outlen) != 1 || peace_asn1_octet_string_to_der(C->ciphertext, C->ciphertext_size, out, outlen) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_ciphertext_from_der(peace_sm2_CIPHERTEXT *C, const uint8_t **in, size_t *inlen)
{
	int ret;
	const uint8_t *d;
	size_t dlen;
	const uint8_t *x;
	const uint8_t *y;
	const uint8_t *hash;
	const uint8_t *c;
	size_t xlen, ylen, hashlen, clen;

	if ((ret = peace_asn1_type_from_der(peace_asn1_TAG_SEQUENCE, &d, &dlen, in, inlen)) != 1)
	{
		if (ret < 0)

			return ret;
	}
	if (peace_asn1_integer_from_der(&x, &xlen, &d, &dlen) != 1 || peace_asn1_length_le(xlen, 32) != 1)
	{

		return E_ERROR;
	}
	if (peace_asn1_integer_from_der(&y, &ylen, &d, &dlen) != 1 || peace_asn1_length_le(ylen, 32) != 1)
	{

		return E_ERROR;
	}
	if (peace_asn1_octet_string_from_der(&hash, &hashlen, &d, &dlen) != 1 || peace_asn1_check(hashlen == 32) != 1)
	{

		return E_ERROR;
	}
	if (peace_asn1_octet_string_from_der(&c, &clen, &d, &dlen) != 1

		|| peace_asn1_length_le(clen, peace_sm2_MAX_PLAINTEXT_SIZE) != 1)
	{

		return E_ERROR;
	}
	if (peace_asn1_length_is_zero(dlen) != 1)
	{

		return E_ERROR;
	}
	memset(C, 0, sizeof(peace_sm2_CIPHERTEXT));
	memcpy(C->point.x + 32 - xlen, x, xlen);
	memcpy(C->point.y + 32 - ylen, y, ylen);
	if (peace_sm2_point_is_on_curve(&C->point) != 1)
	{

		return E_ERROR;
	}
	memcpy(C->hash, hash, hashlen);
	memcpy(C->ciphertext, c, clen);
	C->ciphertext_size = (uint8_t)clen;
	return 1;
}

int peace_sm2_encrypt(const peace_sm2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
{
	peace_sm2_CIPHERTEXT C;

	if (!key || !in || !out || !outlen)
	{

		return E_ERROR;
	}
	if (!inlen)
	{

		return E_ERROR;
	}

	if (peace_sm2_do_encrypt(key, in, inlen, &C) != 1)
	{

		return E_ERROR;
	}
	*outlen = 0;
	if (peace_sm2_ciphertext_to_der(&C, &out, outlen) != 1)
	{

		return E_ERROR;
	}
	return E_OK;
}

int peace_sm2_encrypt_fixlen(const peace_sm2_KEY *key, const uint8_t *in, size_t inlen, int point_size, uint8_t *out, size_t *outlen)
{
	peace_sm2_CIPHERTEXT C;

	if (!key || !in || !out || !outlen)
	{

		return E_ERROR;
	}
	if (!inlen)
	{

		return E_ERROR;
	}

	if (peace_sm2_do_encrypt_fixlen(key, in, inlen, point_size, &C) != 1)
	{

		return E_ERROR;
	}
	*outlen = 0;
	if (peace_sm2_ciphertext_to_der(&C, &out, outlen) != 1)
	{

		return E_ERROR;
	}
	return 1;
}

int peace_sm2_decrypt(const peace_sm2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
{
	peace_sm2_CIPHERTEXT C;

	if (!key || !in || !out || !outlen)
	{

		return E_ERROR;
	}
	if (peace_sm2_ciphertext_from_der(&C, &in, &inlen) != 1 || peace_asn1_length_is_zero(inlen) != 1)
	{

		return E_ERROR;
	}
	if (peace_sm2_do_decrypt(key, &C, out, outlen) != 1)
	{

		return E_ERROR;
	}
	return E_OK;
}



int peace_sm2_do_sign_fast(const peace_sm2_Fn d, const uint8_t dgst[32], peace_sm2_SIGNATURE *sig)
{
	peace_sm2_JACOBIAN_POINT R;
	peace_sm2_BN e;
	peace_sm2_BN k;
	peace_sm2_BN x1;
	peace_sm2_BN r;
	peace_sm2_BN s;

	peace_sm2_bn_from_bytes(e, dgst);
	if (peace_sm2_bn_cmp(e, peace_sm2_N) >= 0)
	{
		peace_sm2_bn_sub(e, e, peace_sm2_N);
	}

	do
	{
		if (peace_sm2_fn_rand(k) != 1)
		{

			return E_ERROR;
		}
	} while (peace_sm2_bn_is_zero(k));

	peace_sm2_jacobian_point_mul_generator(&R, k);
	peace_sm2_jacobian_point_get_xy(&R, x1, NULL);

	peace_sm2_fn_add(r, e, x1);

	peace_sm2_bn_add(s, k, r);
	peace_sm2_fn_mul(s, s, d);
	peace_sm2_fn_sub(s, s, r);

	peace_sm2_bn_to_bytes(r, sig->r);
	peace_sm2_bn_to_bytes(s, sig->s);
	return 1;
}

Std_ReturnType peace_sm2_sign(uint8_t *buf, uint32_t buf_length, uint8_t *Private_Key, uint8_t *Publickey, uint8_t *Sig_Result, uint8_t *Sig_R, uint8_t *Sig_S, size_t *siglen)
{
	Std_ReturnType ret = E_OK;
	char *id = peace_sm2_DEFAULT_ID;
	peace_sm2_KEY key;
	size_t len;

	peace_sm2_SIGN_CTX sign_ctx;
	uint8_t i = 0;
	len = buf_length;

	for (i = 0; i < 32; i++)
	{
		key.private_key[i] = Private_Key[i];
		key.public_key.x[i] = Publickey[i];
		key.public_key.y[i] = Publickey[i + 32];
	}

	ret = peace_sm2_sign_init(&sign_ctx, &key, id, strlen(id));

	ret = peace_sm2_sign_update(&sign_ctx, buf, len);
	{
		ret = E_NOT_OK;
	}

	ret = peace_sm2_sign_finish(&sign_ctx, Sig_Result, Sig_R, Sig_S, siglen);

	return ret;
}

/**
 * @brief Verifies the signature using SM2 algorithm.
 *
 * This function initializes the SM2 verification context,
 * processes the input data, and checks the signature validity.
 *
 * @param[in] buf Pointer to the input buffer containing the message.
 * @param[in] bufLength Length of the input buffer.
 * @param[in] privateKey Pointer to the private key used for the verification.
 * @param[in] publicKey Pointer to the public key associated with the private key.
 * @param[out] sigVerifyResult Pointer to the buffer where the verification result will be stored.
 *
 * @return Std_ReturnType E_OK if the verification is successful, otherwise E_NOT_OK.
 */

Std_ReturnType peace_sm2_verify(uint8_t *buf, uint32_t bufLength, uint8_t *privateKey, uint8_t *publicKey, uint8_t *sigVerifyResult, size_t sigLen)
{
	Std_ReturnType verifyRet = E_OK;
	const char *id = peace_sm2_DEFAULT_ID; /**< Default identifier for the verification */
	peace_sm2_KEY key;					 /**< Structure to hold the SM2 key pair */
	peace_sm2_SIGN_CTX verifyCtx;			 /**< Context structure for the signature verification */

	int verifyReturn; /**< Verification result */

	for (int i = 0; i < 32; i++)
	{
		key.private_key[i] = privateKey[i];
		key.public_key.x[i] = publicKey[i];
		key.public_key.y[i] = publicKey[i + 32];
	}

	if (peace_sm2_verify_init(&verifyCtx, &key, id, strlen(id)) != 1)
	{
		verifyRet = E_NOT_OK; /**< Set return value to E_NOT_OK on initialization failure */
	}

	if (peace_sm2_verify_update(&verifyCtx, buf, bufLength) != 1)
	{
		verifyRet = E_NOT_OK; /**< Set return value to E_NOT_OK on update failure */
	}

	if ((verifyReturn = peace_sm2_verify_finish(&verifyCtx, sigVerifyResult, sigLen)) < 0)
	{
		verifyRet = E_NOT_OK; /**< Set return value to E_NOT_OK on finish failure */
	}

	if (verifyReturn == 1)
	{
		verifyRet = E_OK; /**< Set return value to E_NOT_OK if the verification failed */
	}

	return verifyRet; /**< Return the result of the verification */
}
